home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / MacPerl 5.1.3 / Mac_Perl_513_src / perl5.002 / SubLaunch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-26  |  9.7 KB  |  407 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    SubLaunch        -    Call ToolServer
  3. File        :    SubLaunch.c        -    The code
  4. Author    :    Matthias Neeracher
  5. Started    :    06Dec91                                Language    :    MPW C/C++
  6. Modified    :    06Dec91    MN    
  7.                 07Mar92    MN    
  8.                 25Nov93    MN    Mo' better spin
  9.                 11Jun95    MN Metrowerks version using inline assembly
  10. Last        :    11Jun95
  11.  
  12. Copyright (c) 1991-1995 Matthias Neeracher
  13.  
  14.     You may distribute under the terms of the Perl Artistic License,
  15.     as specified in the README file.
  16.  
  17. *********************************************************************/
  18.  
  19. /* We need glue for Gestalt, but not for the rest of the stuff */
  20.  
  21. #include <GestaltEqu.h>
  22. #include <TFileSpec.h>
  23. #include <GUSI.h>
  24.  
  25. #include <Types.h>
  26. #include <Processes.h>
  27. #include <Events.h>
  28. #include <AppleEvents.h>
  29. #include <CursorCtl.h>
  30. #include <Resources.h>
  31. #include <QuickDraw.h>
  32. #include <Folders.h>
  33. #include <Errors.h>
  34. #include <Script.h>
  35. #include <TextUtils.h>
  36.  
  37. #include <string.h>
  38.  
  39. #define MAC_CONTEXT
  40.  
  41. #include "SubLaunch.h"
  42. #include "macish.h"
  43.  
  44. #define FAILOSERR(call)    if (err = call)    return err
  45. #define ToolServer    'MPSX'
  46.  
  47. /* The following stuff is adapted from Jens Peter Alfke's SignatureToApp code */
  48.  
  49. static OSErr ToolServerRunning(ProcessSerialNumber *psn)
  50. {
  51.     OSErr err;
  52.     ProcessInfoRec info;
  53.     
  54.     psn->highLongOfPSN = 0;
  55.     psn->lowLongOfPSN  = kNoProcess;
  56.     do    {
  57.         FAILOSERR(GetNextProcess(psn));
  58.         info.processInfoLength     = sizeof(info);
  59.         info.processName             = nil;
  60.         info.processAppSpec         = nil;
  61.         FAILOSERR(GetProcessInformation(psn,&info));
  62.     } while(info.processSignature != ToolServer);
  63.  
  64.     *psn = info.processNumber;
  65.     
  66.     return noErr;
  67. }
  68.  
  69. static OSErr GetSysVolume(short *vRefNum)
  70. {
  71.     long dir;
  72.     
  73.     return FindFolder(kOnSystemDisk, kSystemFolderType, false, vRefNum, &dir);
  74. }
  75.  
  76.  
  77. static OSErr GetIndVolume(short index, short *vRefNum)
  78. {
  79.     OSErr             err;
  80.     ParamBlockRec     pb;
  81.     
  82.     pb.volumeParam.ioNamePtr     = nil;
  83.     pb.volumeParam.ioVolIndex     = index;
  84.     
  85.     FAILOSERR(PBGetVInfoSync(&pb));
  86.     
  87.     *vRefNum = pb.volumeParam.ioVRefNum;
  88.     
  89.     return noErr;
  90. }
  91.  
  92. static OSErr VolHasDesktopDB(short vRefNum, Boolean * hasDesktop)
  93. {
  94.     OSErr                         err;
  95.     HParamBlockRec             pb;
  96.     GetVolParmsInfoBuffer     info;
  97.     
  98.     pb.ioParam.ioNamePtr     = nil;
  99.     pb.ioParam.ioVRefNum     = vRefNum;
  100.     pb.ioParam.ioBuffer         = (Ptr)&info;
  101.     pb.ioParam.ioReqCount     = sizeof(GetVolParmsInfoBuffer);
  102.     
  103.     FAILOSERR(PBHGetVolParmsSync(&pb));
  104.  
  105.     *hasDesktop = (info.vMAttrib & (1 << bHasDesktopMgr))!=0;
  106.     
  107.     return noErr;
  108. }
  109.  
  110. static OSErr FindAppOnVolume(short vRefNum, FSSpec *file)
  111. {
  112.     OSErr     err;
  113.     DTPBRec     pb;
  114.     
  115.     /* Get Acess path to Desktop database on this volume */
  116.     
  117.     pb.ioVRefNum         = vRefNum;
  118.     pb.ioNamePtr         = nil;
  119.     FAILOSERR(PBDTGetPath(&pb));
  120.     
  121.     pb.ioIndex             = 0;
  122.     pb.ioFileCreator     = ToolServer;
  123.     pb.ioNamePtr         = file->name;
  124.     switch (err = PBDTGetAPPLSync(&pb))    {
  125.     case noErr:
  126.         file->vRefNum     = vRefNum;
  127.         file->parID     = pb.ioAPPLParID;
  128.     
  129.         return noErr;
  130.     case fnfErr:
  131.         return afpItemNotFound;                        /* Bug in PBDTGetAPPL            */
  132.     default:
  133.         return err;
  134.     }
  135. }
  136.  
  137. /* LaunchApplication in 32 bit everything environment    */
  138.  
  139. #if !defined(powerc) && !defined(__powerc)
  140. pascal OSErr WrappedLaunchApplication(const LaunchParamBlockRec *LaunchParams);
  141. #else
  142. #define WrappedLaunchApplication LaunchApplication
  143. #endif
  144.  
  145. static OSErr LaunchIt(const FSSpecPtr fileSpec, ProcessSerialNumber *psn )
  146. {
  147.     OSErr                     err;
  148.     LaunchParamBlockRec     pb;
  149.     
  150.     pb.launchBlockID             = extendedBlock;
  151.     pb.launchEPBLength         = extendedBlockLen;
  152.     pb.launchFileFlags         = launchNoFileFlags;
  153.     pb.launchControlFlags    = launchContinue | launchNoFileFlags | launchDontSwitch;
  154.     pb.launchAppSpec             = fileSpec;
  155.     pb.launchAppParameters    = nil;
  156.     
  157.     FAILOSERR(LaunchApplication(&pb));
  158.  
  159.     *psn = pb.launchProcessSN;
  160.     
  161.     return noErr;
  162. }
  163.  
  164. /* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
  165. static OSErr LaunchToolServer(ProcessSerialNumber *psn)
  166. {
  167.     OSErr     err;
  168.     short     sysVRefNum, vRefNum, index;
  169.     FSSpec     file;
  170.     Boolean     hasDesktopDB;
  171.     
  172.     /* See if ToolServer is already running:                    */
  173.     err    = ToolServerRunning(psn);
  174.     
  175.     if    (err != procNotFound)
  176.         return err;
  177.     
  178.     /* Not running, try to launch it */
  179.     
  180.     FAILOSERR(GetSysVolume(&sysVRefNum));
  181.     vRefNum     = sysVRefNum;
  182.     for (index = 0; !err; err = GetIndVolume(++index,&vRefNum)) {
  183.         if (!index || vRefNum != sysVRefNum) {
  184.             FAILOSERR(VolHasDesktopDB(vRefNum,&hasDesktopDB));
  185.             if (hasDesktopDB)    
  186.                 switch (err = FindAppOnVolume(vRefNum, &file))    {
  187.                 case noErr:
  188.                     return LaunchIt(&file,psn);
  189.                 case afpItemNotFound:
  190.                     break;
  191.                 default:
  192.                     return err;
  193.                 }
  194.         }
  195.     }
  196.     switch (err)    {
  197.     case nsvErr:
  198.     case afpItemNotFound:
  199.         return fnfErr;
  200.     default:
  201.         return err;
  202.     }
  203. }
  204.  
  205. typedef enum {
  206.     dontKnow,
  207.     canRun,
  208.     cantRun
  209. } featureCheck;
  210.  
  211. static featureCheck    requiredFeatures    =    dontKnow;
  212.  
  213. #define HASBIT(bit) (answer&(1<<bit))
  214. #define GESTALT(sel) !Gestalt(sel, &answer)
  215.  
  216. OSErr ValidateFeatures()
  217. {
  218.     long answer;
  219.     
  220.     switch (requiredFeatures)    {
  221.     case canRun:
  222.         return noErr;
  223.     case cantRun:
  224.         return gestaltUnknownErr;
  225.     case dontKnow:
  226.         if (    GESTALT(gestaltAppleEventsAttr)                            && 
  227.                     HASBIT(gestaltAppleEventsPresent)                     &&
  228.                  GESTALT(gestaltFindFolderAttr)                            &&
  229.                     HASBIT(gestaltFindFolderPresent)                     &&
  230.                 GESTALT(gestaltOSAttr)                                        &&
  231.                     HASBIT(gestaltLaunchCanReturn)                        &&
  232.                     HASBIT(gestaltLaunchFullFileSpec)                    &&
  233.                     HASBIT(gestaltLaunchControl)                            &&
  234.                 GESTALT(gestaltFSAttr)                                        &&
  235.                     HASBIT(gestaltHasFSSpecCalls)
  236.         )
  237.             requiredFeatures    =    canRun;
  238.         else
  239.             requiredFeatures     =     cantRun;
  240.         
  241.         return ValidateFeatures();
  242.     }
  243. }
  244.  
  245. #define FAILOSERR(call)    if (err = call)    return err
  246.  
  247. /* Create a temporary file in the temp folder. 
  248. */
  249. OSErr    FSpMakeTempFile(FSSpec * desc)
  250. {
  251.     static int    id    =    0;
  252.  
  253.     OSErr            err;
  254.     
  255.     FAILOSERR(FindFolder(kOnSystemDisk, 'temp', true, &desc->vRefNum, &desc->parID));
  256.     
  257.     *((long *) desc->name)        =    '\007tmp';
  258.     
  259.     do {
  260.         desc->name[4]    =    id / 1000     % 10 + '0';
  261.         desc->name[5]    =    id / 100        % 10 + '0';
  262.         desc->name[6]    =    id / 10        % 10 + '0';
  263.         desc->name[7]    =    id             % 10 + '0';
  264.         
  265.         ++id;
  266.         
  267.         err = HCreate(desc->vRefNum, desc->parID, desc->name, 'TEMP', 'TEXT');
  268.     } while (err == dupFNErr);
  269.     
  270.     return err;
  271. }
  272.             
  273. pascal Boolean SubLaunchIdle(EventRecord * ev, long * sleep, RgnHandle * rgn)
  274. {
  275.     SpinCursor(1);
  276.     
  277.     if (gHandleEvent)
  278.         (*gHandleEvent)(ev);
  279.     else if (ev->what == kHighLevelEvent)
  280.         if (AEProcessAppleEvent(ev)) 
  281.             return true;
  282.         
  283.     *sleep    =    10;
  284.     
  285.     return false;
  286. }
  287.  
  288. #if USESROUTINEDESCRIPTORS
  289. RoutineDescriptor    uSubLaunchIdle = 
  290.         BUILD_ROUTINE_DESCRIPTOR(uppAEIdleProcInfo, SubLaunchIdle);
  291. #else
  292. #define uSubLaunchIdle SubLaunchIdle
  293. #endif
  294.  
  295. static char * Fragments[] = {
  296.     "Directory \'",
  297.     "\'; Begin; ",
  298.     "; End<\'",
  299.     "\' >\'",
  300.     "\' ≥\'",
  301.     "\' ∑\'",
  302.     "\'\n",
  303.     "Dev:Null"
  304. };
  305.  
  306. #define BEGIN_TEXT        Fragments[0]
  307. #define DIRSET_TEXT        Fragments[1]
  308. #define END_TEXT            Fragments[2]
  309. #define STDOUT_TEXT        Fragments[3]
  310. #define STDERR_TEXT        Fragments[4]
  311. #define OUTERR_TEXT        Fragments[5]
  312. #define TERM_TEXT            Fragments[6]
  313. #define DEVNULL_TEXT        Fragments[7]
  314. #define DEVSTRING(dev)    (dev) ? FSp2FullPath(dev) : DEVNULL_TEXT
  315.         
  316. /* Execute the command. Any of the files may be set to NULL */
  317. OSErr SubLaunch(char * commandline, FSSpec * input, FSSpec * output, FSSpec * error, long * status)
  318. {
  319.     OSErr                        err;
  320.     Boolean                    same;
  321.     ProcessSerialNumber    psn;
  322.     ProcessSerialNumber    me;
  323.     AppleEvent                cmd;
  324.     AppleEvent                reply;
  325.     AEAddressDesc            addr;
  326.     acurHandle                acur;
  327.     Handle                    text;
  328.     char *                    segment;
  329.     FSSpec                    vol;
  330.     OSType                    type;
  331.     Size                        size;
  332.     
  333.     /* Check if the system is sexy enough */
  334.     FAILOSERR(ValidateFeatures());
  335.     
  336.     /* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
  337.     FAILOSERR(LaunchToolServer(&psn));
  338.     
  339.     /* It would be disastrous to send the event to ourselves (I know: I tried) */
  340.     FAILOSERR(GetCurrentProcess(&me));
  341.     FAILOSERR(SameProcess(&psn, &me, &same));
  342.     if (same)
  343.         return appMemFullErr;            /* This is a lie. So what ? */
  344.     
  345.     /* Build shell wrapper for command string */
  346.     FAILOSERR(PtrToHand(BEGIN_TEXT, &text, strlen(BEGIN_TEXT)));
  347.     FAILOSERR(Path2FSSpec(":", &vol));
  348.     segment    =    FSp2FullPath(&vol);
  349.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  350.     FAILOSERR(PtrAndHand(DIRSET_TEXT, text, strlen(DIRSET_TEXT)));
  351.     FAILOSERR(PtrAndHand(commandline, text, strlen(commandline)));
  352.     FAILOSERR(PtrAndHand(END_TEXT, text, strlen(END_TEXT)));
  353.     segment = DEVSTRING(input);
  354.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  355.     segment = DEVSTRING(output);
  356.     if (    output && error 
  357.         && output->vRefNum == error->vRefNum
  358.         && output->parID   == error->parID
  359.         && EqualString(output->name, error->name, false, true)
  360.     ) {
  361.         FAILOSERR(PtrAndHand(OUTERR_TEXT, text, strlen(OUTERR_TEXT)));
  362.         FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  363.     } else {
  364.         FAILOSERR(PtrAndHand(STDOUT_TEXT, text, strlen(STDOUT_TEXT)));
  365.         FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  366.         FAILOSERR(PtrAndHand(STDERR_TEXT, text, strlen(STDERR_TEXT)));
  367.         DEVSTRING(error);
  368.         FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  369.     }
  370.     FAILOSERR(PtrAndHand(TERM_TEXT, text, strlen(TERM_TEXT)));
  371.     
  372.     /* Build the AppleEvent */
  373.     FAILOSERR(
  374.         AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(psn), &addr));
  375.     FAILOSERR(
  376.         AECreateAppleEvent('misc', 'dosc', &addr, 
  377.             kAutoGenerateReturnID, kAnyTransactionID, 
  378.             &cmd));
  379.     HLock(text);
  380.     FAILOSERR(
  381.         AEPutParamPtr(&cmd, '----', typeChar, *text, GetHandleSize(text)));
  382.     DisposHandle(text);
  383.     
  384.     /* Send it */
  385.     acur    =    (acurHandle) GetResource('acur', 128);
  386.     DetachResource((Handle) acur);
  387.     InitCursorCtl(acur);
  388.     err    =    
  389.         AESend(
  390.             &cmd, &reply, kAEWaitReply+kAENeverInteract, 
  391.             kAENormalPriority, kNoTimeOut, 
  392.             (AEIdleUPP) &uSubLaunchIdle, nil);
  393.         
  394.     if (AEGetParamPtr(&reply, 'stat', typeLongInteger, &type, (Ptr) status, 4, &size))
  395.         *status = 0;
  396.         
  397.     AEDisposeDesc(&cmd);
  398.     AEDisposeDesc(&addr);
  399.     AEDisposeDesc(&reply);
  400.     
  401.     DisposeHandle((Handle) acur);
  402.     
  403.     InitCursorCtl(NULL);
  404.     
  405.     return err;
  406. }
  407.